package com.tianji.promotion.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * TODO：线程池 促销配置类，用于配置与促销相关的线程池
 */
@Slf4j
@Configuration
public class PromotionConfig {

    /**
     * 创建一个用于生成兑换码的线程池执行器
     *
     * @return 生成的线程池执行器
     */
    @Bean
    public Executor generateExchangeCodeExecutor() {
        // 创建一个线程池任务执行器
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();

        // 1. 设置核心线程池大小
        // 核心线程池是线程池始终保持存活的线程数量，即使这些线程处于空闲状态
        executor.setCorePoolSize(2);

        // 2. 设置最大线程池大小
        // 当任务队列满时，线程池可以创建的最大线程数量
        executor.setMaxPoolSize(5);

        // 3. 设置队列大小
        // 用于存储等待执行的任务的队列的最大容量
        executor.setQueueCapacity(200);

        // 4. 设置线程名称前缀
        // 方便在日志中区分不同线程池的线程
        executor.setThreadNamePrefix("exchange-code-handler-");

        // 5. 设置拒绝策略
        // 当线程池和任务队列都满时，新提交的任务的处理策略
        // CallerRunsPolicy 表示由调用线程来执行该任务
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());

        // 初始化线程池执行器
        executor.initialize();

        // 返回配置好的线程池执行器
        return executor;
    }

    /**
     * 创建一个用于计算折扣方案的线程池执行器
     *
     * @return 生成的线程池执行器
     */
    @Bean
    public Executor discountSolutionExecutor() {
        // 创建一个线程池任务执行器
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 1.核心线程池大小
        // 核心线程池是线程池始终保持存活的线程数量，即使这些线程处于空闲状态
        // 设置核心线程数为 12，意味着线程池会一直保持 12 个线程处于活跃状态
        executor.setCorePoolSize(12);
        // 2.最大线程池大小
        // 当任务队列满时，线程池可以创建的最大线程数量
        // 这里设置最大线程数和核心线程数相同，表明线程池不会额外创建线程
        executor.setMaxPoolSize(12);
        // 3.队列大小
        // 用于存储等待执行的任务的队列的最大容量
        // 设置队列容量为 99999，可存储大量等待执行的折扣计算任务
        executor.setQueueCapacity(99999);
        // 4.线程名称
        // 方便在日志中区分不同线程池的线程
        // 设置线程名称前缀，这样在日志中可以清晰看到是该线程池中的线程在执行任务
        executor.setThreadNamePrefix("discount-solution-calculator-");
        // 5.拒绝策略
        // 当线程池和任务队列都满时，新提交的任务的处理策略
        // AbortPolicy 表示当线程池和队列都满时，新任务会被拒绝并抛出异常
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
        // 初始化线程池执行器
        executor.initialize();
        // 返回配置好的线程池执行器
        return executor;
    }

}